#pragma once

#include "Types.h"
#include "Property.h"
#include "ObjectProperty.h"
#include "DropDown.h"

namespace My {

template <typename T>
struct EnumItem {
	ResourceString	name;
	T				value;
};

template <typename T>
class EnumControlBase : public DropDown {
public:
	EnumControlBase(BasicProperty<T> &, const EditableList &);
public:
	virtual String GetItem(My::Size);
	virtual bool GetCurrent(int &);
	virtual int SetCurrent(int);
	virtual void HandleUpdateUI();
protected:
	virtual EnumItem<T> GetEnumItem(My::Size) = 0;
protected:
	BasicProperty<T> &	m_Property;
	EditableList		m_Objects;
};

/**
 * Use this control as TypedControl<T> for enumeration 
 * types which items don't depend on objects.
 */
template <typename T>
class EnumTypeControl : public EnumControlBase<T> {
public:
	EnumTypeControl(BasicProperty<T> &, const EditableList &, const String & def = String());
protected:
	virtual My::Size GetItemCount();
	virtual String GetDefaultItem();
	virtual EnumItem<T> GetEnumItem(My::Size);
public:
	static EnumItem<T>	Items[];
private:
	String	m_Default;
};

#define SPECIALIZE_ENUM_TYPE_CONTROL(type) \
	template <> \
	class My::TypedControl<type> : public My::EnumTypeControl<type> { \
	public: \
		TypedControl(BasicProperty<type> & p, const EditableList & list) \
			: EnumTypeControl<type>(p, list) { } \
	};

#define SPECIALIZE_ENUM_TYPE_CONTROL_DEFAULT(type, DefaultString) \
	template <> \
	class My::TypedControl<type> : public My::EnumTypeControl<type> { \
	public: \
		TypedControl(BasicProperty<type> & p, const EditableList & list) \
			: EnumTypeControl<type>(p, list, DefaultString) { } \
	};

/**
 * Base class for properties that define
 * enumeration themselves.
 */
template <typename T>
class EnumPropertyBase : public virtual BasicProperty<T> {
public:
	virtual Size GetItemCount(const EditableList &) = 0;
	virtual String GetDefaultItem(const EditableList &) = 0;
	virtual EnumItem<T> GetEnumItem(const EditableList &, Size) = 0;
public:
	virtual Widget * CreateControl(const EditableList &);
	virtual void FreeControl(Widget *);
};

/**
 * Control used to edit EnumProperties.
 */
template <typename T>
class EnumPropertyControl : public EnumControlBase<T> {
public:
	EnumPropertyControl(EnumPropertyBase<T> &, const EditableList &);
protected:
	virtual My::Size GetItemCount();
	virtual String GetDefaultItem();
	virtual BasicProperty<T> & GetProperty();
	virtual EnumItem<T> GetEnumItem(My::Size);
private:
	EnumPropertyBase<T> &	m_Property;
};

/**
 * Defines enumeration by a static array 
 * ending with {"", T()}
 */
template <typename T>
class EnumProperty : 
	public EnumPropertyBase<T>,
	public PropertyImpl<T>
{
public:
	EnumProperty(const EnumItem<T> items[], const String & def);
protected:
	EnumProperty();
	void Init(const EnumItem<T> items[], const String & def);
protected:
	virtual Size GetItemCount(const EditableList &);
	virtual String GetDefaultItem(const EditableList &);
	virtual EnumItem<T> GetEnumItem(const EditableList &, Size);
private:
	const EnumItem<T> *		m_pItems;
	Size					m_Count;
	String					m_Default;
};

} // My

#include "Impl/EnumProperty.inl"

